summaryrefslogtreecommitdiff
path: root/app/api/auth/[...nextauth]/route.ts
blob: cd91774ca914c87e982d36b1788026f3c28e03b5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
// (1) next-auth에서 필요한 타입들을 import
import NextAuth, {
  NextAuthOptions,         // authOptions에 쓸 타입
  Session,
  User
} from 'next-auth'
import { JWT } from "next-auth/jwt"

import CredentialsProvider from 'next-auth/providers/credentials'

import { verifyExternalCredentials, verifyOtp } from '@/lib/users/verifyOtp'

// 1) 모듈 보강 선언
declare module "next-auth" {
  /**
   * Session 객체를 확장
   */
  interface Session {
    user: {
      /** 우리가 필요로 하는 user id */
      id: string

      // 기본적으로 NextAuth가 제공하는 name/email/image 필드
      name?: string | null
      email?: string | null
      image?: string | null
      companyId?: number | null
      domain?: string | null

    }
  }

  /**
   * User 객체를 확장
   */
  interface User {
    id: string
    imageUrl?: string | null
    companyId?: number | null
    domain?: string | null
    // 필요한 필드를 추가로 선언 가능
  }
}

// (2) authOptions에 NextAuthOptions 타입 지정
export const authOptions: NextAuthOptions = {
  providers: [
    CredentialsProvider({
      name: 'Credentials',
      credentials: {
        email: { label: 'Email', type: 'text' },
        code: { label: 'OTP code', type: 'text' },
      },
      async authorize(credentials, req) {
        const { email, code } = credentials ?? {}

        // OTP 검증
        const user = await verifyOtp(email ?? '', code ?? '')
        if (!user) {
          return null
        }

        return {
          id: String(user.id ?? email ?? "dts"),
          email: user.email,
          imageUrl: user.imageUrl ?? null,
          name: user.name,   // DB에서 가져온 실제 이름
          companyId: user.companyId,   // DB에서 가져온 실제 이름
          domain: user.domain,   // DB에서 가져온 실제 이름
        }
      },
    }),
    // 새로 추가할 ID/비밀번호 provider
    CredentialsProvider({
      id: 'credentials-password',
      name: 'Username Password',
      credentials: {
        username: { label: "Username", type: "text" },
        password: { label: "Password", type: "password" }
      },
      async authorize(credentials, req) { // req 매개변수 추가
        if (!credentials?.username || !credentials?.password) {
          return null;
        }
        
        try {
          // 여기서 외부 서비스 API를 호출하여 사용자 인증
          const user = await verifyExternalCredentials(
            credentials.username,
            credentials.password
          );
          
          if (user) {
            return {
              id: String(user.id), // id를 string으로 변환
              name: user.name,
              email: user.email,
              // 첫 번째 provider와 동일한 필드 구조 유지
              imageUrl: user.imageUrl ?? null,
              companyId: user.companyId,
              domain: user.domain
            };
          }
          return null;
        } catch (error) {
          console.error("Authentication error:", error);
          return null;
        }
      }
    })
  ],
  // (3) session.strategy는 'jwt'가 되도록 선언
  //     필요하다면 as SessionStrategy 라고 명시해줄 수도 있음
  //     예) strategy: 'jwt' as SessionStrategy
  session: {
    strategy: 'jwt',
  },
  callbacks: {
    // (4) 콜백에서 token, user, session 등의 타입을 좀 더 명시해주고 싶다면 아래처럼 destructuring에 제네릭/타입 지정
    async jwt({ token, user }: { token: JWT; user?: User }) {
      if (user) {
        token.id = user.id
        token.email = user.email
        token.name = user.name
        token.companyId = user.companyId
        token.domain = user.domain
          ; (token as any).imageUrl = (user as any).imageUrl
      }
      return token
    },
    async session({ session, token }: { session: Session; token: JWT }) {
      if (token) {
        session.user = {
          id: token.id as string,
          email: token.email as string,
          name: token.name as string,
          domain: token.domain as string,
          companyId: token.companyId as number,
          image: (token as any).imageUrl ?? null
        }
      }
      return session
    },
  },
}

const handler = NextAuth(authOptions)

export { handler as GET, handler as POST }